--[[
--定时器管理
	1指定时间后运行1次func
	2指定时间循环运行func
	3删除定时func
	4取指定定时器距离下次触发还有多少时间

	5指定某天执行func
	6每天指定时间执行func

--]]

---------------------------------------------------------
-- class
---------------------------------------------------------
local Timer = class("Timer")

function Timer:ctor(interval)

    self.interval = interval or 1 --定时器每步时间间隔默认1秒
    self.co_list = {} --定时器列表
    self.timer_list = {} --定时器列表
    setmetatable(self.timer_list, {__mode="v"}) --弱表在下次gc时会删除不用的记录

    self.co = nil
end


--[[
--注册定时器与回调函数
timer_info = {
	sec 过多少秒后执行
	callback 执行的函数
	loop 是否循环
	param 参数
	stop 是否停止定时器

	do_next_date 是否明天继续
	do_next_week 是否下周继续
}
返回协程句柄
--]]
function Timer:start(timer_info)
    if self.co then
        --timer只允许一个定时器存在
        self:stop()
    end
    --sec, callback, param, loop
    local sec = timer_info.sec
    local callback = timer_info.callback
    local param = timer_info.param
    timer_info.fisrt = true --是否第一次
    timer_info.cur_sec = 0
    local cur_sec = 0
    if not sec then
        g.log:waring("Timer:start sec is nil!", timer_info)
        return
    end
    if(type(sec)~="number" or sec<=0) then
        g.log:waring("Timer:start sec<=0 the time is small then cur_time!", timer_info)
        return
    end
    if(not callback or type(callback)~= "function") then
        print("Timer:start callback param err", timer_info)
        return
    end
    local co = g.fork(function()
        while true do
            if timer_info.stop then
                --定时器结束
                break
            end
            g.sleep(self.interval*100)
            cur_sec = cur_sec + self.interval
            timer_info.cur_sec = cur_sec
            if  cur_sec >= sec then
                cur_sec = 0
                timer_info.cur_sec = cur_sec
                if timer_info.do_next_date then
                    timer_info.sec = 24*3600
                elseif timer_info.do_next_week then
                    timer_info.sec = 24*3600*7
                end
                timer_info.fisrt = false --执行了1次
                callback(param)
            end
            if not timer_info.fisrt and not timer_info.loop then
                break
            end
        end
        --print("close timer ", timer_info)
        timer_info = nil
    end)
    timer_info.co = co
    table.insert(self.timer_list, timer_info)
    self.co = co
    --return co
end

--[[
--删除回调注册
--co:定时器句柄
--]]
function Timer:stop()
    local co = self.co
    if not self.co then return end
    for k, v in pairs(self.timer_list) do
        if v.co == co then
            v.stop = true
        end
    end
end

--定时器还剩余多少时间到下次触发
function Timer:leftTime()
    local co = self.co
    if not co then
        return 0
    end
    for k, v in pairs(self.timer_list) do
        if v.co == co then
            return v.sec - v.cur_sec
        end
    end
    return 0
end

--对skynet.fork 包装一下
function Timer:delay(sec, func)
    if not func or type(func) ~= "function" then
        g.log:error("fork func in nil")
        return
    end
    g.fork(function()
        g.sleep(sec*100)
        func()
    end)
end

--[[
--定义一个任务，指定日期时间运行, 每周指定时间， 每天指定时间
task = {
	time = {
	        year = now.year ,
	        month = now.month ,
	        day = now.day,
	        hour = , 
	        min = ,
	        sec = ,
	} 指定执行的时间
	callback 执行的函数
	loop 是否循环
	param 参数
	stop 是否停止定时器
	do_next_date 是否明天继续
	do_next_week 是否下周继续
}
--]]
function Timer:startTask(task)
    if not task or not task.time then
        print("Time:startTask 参数错误", task)
        return
    end
    local ct = os.time()
    local now = os.date("*t", ct)
    now.time = ct
    local ti = task.time
    --取目标时间与现在的差值(秒)
    local nt = {
        year = now.year ,
        month = now.month,
        day = now.day,
        hour = ti.hour or 0,
        min = ti.min or 0,
        sec = ti.sec,
    }
    --每周几执行
    if ti.wday then
        -- set week
        assert(ti.day == nil and ti.month == nil)
        nt.day = nt.day + ti.wday - now.wday
    else
        --指定某天执行
        -- set day, no week day
        if ti.day then
            nt.day = ti.day
        end
        if ti.month then
            nt.month = ti.month
        end
    end
    --print(os.date("*t", os.time(nt)))
    local task_time = os.time(nt)
    local difftime = task_time - now.time
    task.sec = difftime --多少秒后执行
    --设置定时器
    return self:start(task)
end



return Timer

